package battleship_client;

import battleship_client.screens.SelectScreen;
import battleship_client.screens.GameScreen;
import battleship_client.screens.DataScreen;
import battleship_client.screens.LoginScreen;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.awt.Color;

/**
 *
 * @author jalejandrovc
 */
public class Validator {

    Validator(Controller w) {
        controller = w;
    }
    private Controller controller;

    /**
     * Counts the number of letters in a String
     * @param str the String
     * @return the number of letters
     */
    private int countString(String str) {
        int counter = 0;
        for (int i = 0; i < str.length(); i++) {
            if (Character.isLetter(str.charAt(i))) {
                counter++;
            }
        }
        return counter;
    }

    /**
     * Validates the login data. If valid, calls the WindowHandler's login method.
     * @param user the username
     * @param password the password
     */
    public void validateLogin(String user, char[] password, boolean chkIsAdmin, LoginScreen loginScreen) {
        if (countString(user) < 6) {
            loginScreen.setLblUsernameErrorText("Username must be at least 6 characters long.");
        }
        if (password.length < 6) {
            loginScreen.setLblPasswordErrorText("Password must be at least 6 characters long.");
        } else {
            if (!chkIsAdmin) {
                controller.login(user, password);
            } else {
                controller.loginAdmin(user, password);
            }
        }
    }

    /**
     * Checks if the mails is correctly written
     * @param mail the mail
     * @return true if the mail is written correctly
     */
    private boolean filterMail(String mail) {
        String expression = "^[\\w\\-]([\\.\\w])+[\\w]+@([\\w\\-]+\\.)+[A-Z]{2,4}$";
        CharSequence inputStr = mail;
        Pattern pattern = Pattern.compile(expression, Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(inputStr);
        return matcher.matches();
    }

    /**
     * Checks if the name contains only letters
     * @param name the name
     * @return true if it contains only letters
     */
    private boolean checkName(String name) {
        return Pattern.matches("[a-zA-Z]+", name);
    }

    /**
     * Checks if two passwords are equal
     * @param password1 the first password
     * @param password2 the second password
     * @return true if the are equal
     */
    private boolean checkPasswords(char[] password1, char[] password2) {
        if (password1.length != password2.length) {
            return false;
        }
        for (int i = 0; i < password1.length; i++) {
            if (password1[i] != password2[i]) {
                return false;
            }
        }
        return true;
    }

    /**
     * Validates the personal data input. If valid, calls the corresponding WindowHandler method.
     * @param user the username
     * @param name the name of the user
     * @param password the password
     * @param repeatPassword the repeated password
     * @param mail the e-mail
     * @param newUser a flag to check if the method is called to create a new user or change
     * the data of an existing one.
     */
    public void validatePersonalData(String name, String user, char[] password, char[] repeatPassword, String mail, boolean newUser, DataScreen dataScreen) {
        boolean correct = true;
        if (user.equals("") || name.equals("") || password.length == 0 || mail.equals("")) {
            dataScreen.setLblError("All fields must be filled.");
            correct = false;
        } else if (user.length() < 6 || name.length() < 6 || password.length < 6 || mail.length() < 6) {
            dataScreen.setLblError("All fields must be at least 6 characters long.");
            correct = false;
        } else if (countString(user) < 3 || countString(name) < 3) {
            dataScreen.setLblError("Username and Name must contain at least 3 letters.");
        } else if (!checkPasswords(password, repeatPassword)) {
            dataScreen.setLblErrorPassword("Passwords do not match.");
            correct = false;
        } else if (containsSpaces(user)) {
            dataScreen.setLblErrorUsername("The username must not contain spaces.");
            correct = false;
        } else if (!filterMail(mail)) {
            dataScreen.setLblErrorEmail("That is not a valid email address");
            correct = false;
        }
        if (newUser && correct) {
            controller.newUser(name, user, password, mail);
        } else if (correct) {
            controller.changeData(name, user, password, mail);
        }
    }

    private boolean containsSpaces(String user) {
        return user.contains(" ");
    }

    private boolean validateShip(boolean val, int shipN, int x, int y, boolean[][] validationMatrix) {
        controller.getSelectScreen().getLblError().setVisible(false);
        if (x < 1 || x > 10 || y < 1 || y > 10) {
            controller.getSelectScreen().getLblError().setText("The coordinates for sized-" + shipN + " ship must be greater than 0 and less than 11.");
            controller.getSelectScreen().getLblError().setVisible(true);
            return false;
        }
        if ((val ? y : x) + shipN > 10) {
            controller.getSelectScreen().getLblError().setText("Sized-" + shipN + " ship was set off the board.");
            controller.getSelectScreen().getLblError().setVisible(true);
            return false;
        }
        boolean valid = true;
        if (val) {
            for (int m = -1; m < (shipN - 1); m++) {
                if (validationMatrix[x][y + m]) {
                    controller.getSelectScreen().getLblError().setText("Two of your boats are overlapping.");
                    controller.getSelectScreen().getLblError().setVisible(true);
                    valid = false;
                } else {
                    validationMatrix[x][y + m] = true;
                }
            }
        } else {
            for (int m = -1; m < (shipN - 1); m++) {
                if (validationMatrix[x + m][y]) {
                    controller.getSelectScreen().getLblError().setText("Two of your boats are overlapping.");
                    controller.getSelectScreen().getLblError().setVisible(true);
                    valid = false;
                } else {
                    validationMatrix[x + m][y] = true;
                }
            }
        }
        return valid;
    }

    public void validateSelection(SelectScreen selectScreen) {
        boolean[][] validationMatrix = new boolean[10][10];
        for (int i = 0; i < 10; i++) {
            for (int j = 0; j < 10; j++) {
                validationMatrix[i][j] = false;
            }
        }
        boolean valid6 = validateShip(selectScreen.isCheck6Selected(), 6, Integer.parseInt(selectScreen.getTxt6X().getText()), Integer.parseInt(selectScreen.getTxt6Y().getText()), validationMatrix);
        boolean valid5 = validateShip(selectScreen.isCheck5Selected(), 5, Integer.parseInt(selectScreen.getTxt5X().getText()), Integer.parseInt(selectScreen.getTxt5Y().getText()), validationMatrix);
        boolean valid4 = validateShip(selectScreen.isCheck4Selected(), 4, Integer.parseInt(selectScreen.getTxt4X().getText()), Integer.parseInt(selectScreen.getTxt4Y().getText()), validationMatrix);
        boolean valid3 = validateShip(selectScreen.isCheck3Selected(), 3, Integer.parseInt(selectScreen.getTxt3X().getText()), Integer.parseInt(selectScreen.getTxt3Y().getText()), validationMatrix);
        boolean valid2 = validateShip(selectScreen.isCheck2Selected(), 2, Integer.parseInt(selectScreen.getTxt2X().getText()), Integer.parseInt(selectScreen.getTxt2Y().getText()), validationMatrix);
        int[] shipsArray = new int[15];
        if (valid6 && valid5 && valid4 && valid3 && valid2) {
            shipsArray[0] = (selectScreen.isCheck2Selected() ? 1 : 0);
            shipsArray[1] = Integer.parseInt(selectScreen.getTxt2X().getText());
            shipsArray[2] = Integer.parseInt(selectScreen.getTxt2Y().getText());
            shipsArray[3] = (selectScreen.isCheck3Selected() ? 1 : 0);
            shipsArray[4] = Integer.parseInt(selectScreen.getTxt3X().getText());
            shipsArray[5] = Integer.parseInt(selectScreen.getTxt3Y().getText());
            shipsArray[6] = (selectScreen.isCheck4Selected() ? 1 : 0);
            shipsArray[7] = Integer.parseInt(selectScreen.getTxt4X().getText());
            shipsArray[8] = Integer.parseInt(selectScreen.getTxt4Y().getText());
            shipsArray[9] = (selectScreen.isCheck5Selected() ? 1 : 0);
            shipsArray[10] = Integer.parseInt(selectScreen.getTxt5X().getText());
            shipsArray[11] = Integer.parseInt(selectScreen.getTxt5Y().getText());
            shipsArray[12] = (selectScreen.isCheck6Selected() ? 1 : 0);
            shipsArray[13] = Integer.parseInt(selectScreen.getTxt6X().getText());
            shipsArray[14] = Integer.parseInt(selectScreen.getTxt6Y().getText());
            controller.selectShips(shipsArray);
        }
    }

    public void validateMove(GameScreen g, String txtX, String txtY) {
        int x = 0, y = 0;
        g.getLblError().setVisible(false);
        try {
            x = Integer.parseInt(txtX) - 1;
            y = Integer.parseInt(txtY) - 1;
            if (x < 0 || x > 9 || y < 0 || y > 9) {
                g.getLblError().setText("The coordinates must be greater than 0 and less than 11");
                g.getLblError().setVisible(true);
            } else if (g.getOpponentPanel()[x][y].getBackground() != Color.blue) {
                g.getLblError().setText("You've already attacked that coordinate!");
                g.getLblError().setVisible(true);
            } else {
                controller.attack(x, y);
            }
        } catch (NumberFormatException ex) {
            g.getLblError().setText("The coordinates must be numbers!");
            g.getLblError().setVisible(true);
        }
    }
}
